package cc.rengu.igas.share.core.service.channel.momp;

import cc.rengu.igas.momp.facade.base.Header;
import cc.rengu.igas.momp.facade.bean.PaymentOrderMchntFeeDiscountInfoBean;
import cc.rengu.igas.momp.facade.request.ComboMchntFeeDiscountRequest;
import cc.rengu.igas.momp.facade.response.ComboMchntFeeDiscountResponse;
import cc.rengu.igas.momp.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.constant.UserSessionConstant;
import cc.rengu.igas.share.common.enums.FeeTypeEnum;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 混合支付(商户手续费优惠)
 * Created by wangcheng on 2021/3/23 11:08
 */
public class ComboMchntFeeDiscountService extends ChannelBaseService {
    @Override
    public Object callPreProc(TxnInfo txnInfo, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        PayOrderInfo payOrderInfo = (PayOrderInfo) GlobalTransUtil.getCacheValue(TransCacheConstant.PAY_ORDER_INFO);
        String feeType;
        String mompProdKey;
        SignAcctInfo signAcctInfo = (SignAcctInfo) GlobalTransUtil.getCacheValue(TransCacheConstant.SIGN_ACCT_INFO);
        if (null != signAcctInfo){
            mompProdKey = txnInfo.getSrcTxnAuthCfg().getTxnNum() + txnInfo.getSrcTxnAuthCfg().getBizType() + signAcctInfo.getSignAcctType();
            feeType = convFeeType(signAcctInfo.getSignAcctType());
        }else if (null != payOrderInfo){
            mompProdKey = payOrderInfo.getTxnNum() + payOrderInfo.getBizType();
            feeType = convFeeType(payOrderInfo.getPayerAcctType());
        }else {
            rglog.error("无法获取营销产品代码，交易失败!");
            return null;
        }
        /* Step1：获取营销产品代码 */
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = sysParamService.getSysParamInfo(orderInfo.getUserOrderInfo().getInstId(), "OPMS_MOMP_PROD_CODE", mompProdKey);
        if (null == sysParam) {
            rglog.info("无法根据<{}>获取营销产品代码，默认不对客及对商户进行营销!", mompProdKey);
            return null;
        }
        /* Step2：获取费率类型 */
        /* Step3：业务请求头 */
        Header header = new Header();
        header.setInstId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID));
        header.setChanlId(ChannelEnum.OPMS.getChannelType());
        header.setSrcSysId(AppParamConstant.SYS_ID);
        header.setBizType(AppParamConstant.DEFAULT_BIZ_TYPE);
        header.setVersion(ShareParamConstant.DUBBO_VSERSION);
        header.setTxnNum(channelCallCfg.getCallChannelTxn());
        header.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM) + channelCallCfg.getCallIndex());
        header.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        header.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        /* Step4：业务请求体 */
        ComboMchntFeeDiscountRequest comboMchntFeeDiscountRequest = new ComboMchntFeeDiscountRequest();
        comboMchntFeeDiscountRequest.setHeader(header);
        comboMchntFeeDiscountRequest.setUserId((String) GlobalTransUtil.getCacheValue(TransCacheConstant.MOMP_USER_INFO));
        comboMchntFeeDiscountRequest.setBizProdCode(sysParam.getParamValue().trim());
        comboMchntFeeDiscountRequest.setMchntOrderId(orderInfo.getUserOrderInfo().getUserOrderId());
        comboMchntFeeDiscountRequest.setTransAmt(orderInfo.getUserOrderInfo().getNeedPayAmt());
        /* Step5：商户订单明细 */
        List<MchntOrderInfo> mchntOrderInfoList = orderInfo.getMchntOrderInfoList();
        List<PaymentOrderMchntFeeDiscountInfoBean> mchntFeeDiscountInfoBeanList = new ArrayList<>();
        MchntService mchntService = new MchntServiceImpl();
        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
            PaymentOrderMchntFeeDiscountInfoBean mchntFeeDiscountInfoBean = new PaymentOrderMchntFeeDiscountInfoBean();
            MchntInfo mchntInfo = mchntService.getMchntInfo(mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo());
            if ("N".equals(mchntInfo.getIndependentDataFlag()) && "11".equals(mchntInfo.getMchntType())) {
                /*非独立清算商户计算手续费上送连锁商户号*/
                rglog.info("非独立清算商户计算手续费上送连锁商户号<{}>", mchntInfo.getChainMchntNo());
                mchntFeeDiscountInfoBean.setMchntNo(mchntInfo.getChainMchntNo());
            } else {
                mchntFeeDiscountInfoBean.setMchntNo(mchntOrderInfo.getMchntNo());
            }
            /*商户清算金额*/
            mchntFeeDiscountInfoBean.setMchntSettleAmt(mchntOrderInfo.getRealSettleAmt());
            /*商户订单金额*/
            mchntFeeDiscountInfoBean.setOrderAmt(mchntOrderInfo.getRealSettleAmt());
            /*手续费计算方式*/
            mchntFeeDiscountInfoBean.setFeeInputMode(mchntOrderInfo.getFeeInputMode());
            /*商户应收手续费*/
            mchntFeeDiscountInfoBean.setMchntFeeReceivable(mchntOrderInfo.getMchntFee());
            /* 费率类型 */
            mchntFeeDiscountInfoBean.setFeeType(feeType);
            /* 业务产品代码 */
            mchntFeeDiscountInfoBean.setBizProdCode(mchntOrderInfo.getBizProdCode());
            /*手续费收取费率*/
            if ("2".equals(mchntOrderInfo.getFeeInputMode())) {
                /*固定收续费上送0*/
                mchntFeeDiscountInfoBean.setMchntFeeReceivableRate("0");
            } else {
                mchntFeeDiscountInfoBean.setMchntFeeReceivableRate(mchntOrderInfo.getFeeRate());
            }
            mchntFeeDiscountInfoBeanList.add(mchntFeeDiscountInfoBean);
        }
        comboMchntFeeDiscountRequest.setFeeOrderDetailList(mchntFeeDiscountInfoBeanList);
        GlobalTransUtil.setCacheValue(TransCacheConstant.MOMP_ORIG_COMB_PAYMENT_TRACE_NO, comboMchntFeeDiscountRequest.getHeader().getTraceNo());
        return comboMchntFeeDiscountRequest;
    }

    @Override
    public PayOrderInfo generatePayOrderInfo(ChannelCallCfg channelCallCfg, OrderInfo orderInfo, Object request) throws Exception {
        ComboMchntFeeDiscountRequest comboMchntFeeDiscountRequest = (ComboMchntFeeDiscountRequest) request;
        PayOrderInfo payOrderInfo = new PayOrderInfo();
        BeanUtil.beanCopy(orderInfo.getUserOrderInfo(), payOrderInfo);
        if (orderInfo.getMchntOrderInfoList().size() == 1) {
            payOrderInfo.setMchntNo(orderInfo.getMchntOrderInfoList().get(0).getMchntNo());
        } else {
            payOrderInfo.setMchntNo(orderInfo.getUserOrderInfo().getGroupMchntNo());
        }
        payOrderInfo.setTxnNum(channelCallCfg.getTxnNum());
        payOrderInfo.setBizType(channelCallCfg.getBizType());
        payOrderInfo.setSysSeqNum(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setOrderCcy(orderInfo.getUserOrderInfo().getOrderCcy());
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        payOrderInfo.setChannelSeqNum(comboMchntFeeDiscountRequest.getHeader().getTraceNo());
        payOrderInfo.setChannelReconKey(comboMchntFeeDiscountRequest.getHeader().getTraceNo());
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setPayType(PayTypeEnum.OTHER.getPayType());
        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        payOrderInfo.setUserId(orderInfo.getUserOrderInfo().getUserId());

        return payOrderInfo;
    }

    @Override
    public Object callProc(ChannelCallCfg channelCallCfg, Object request) throws Exception {
        ComboMchntFeeDiscountRequest comboMchntFeeDiscountRequest = (ComboMchntFeeDiscountRequest) request;
        /* Step1：调用营销模块联合营销接口，获取对客及对商户手续费营销结果 */
        Result<ComboMchntFeeDiscountResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if (AppParamConstant.YES.equals(channelCallCfg.getSyncCallFlag())) {
            /* Step1.1：异步调用 */
            int iReturnCode;
            int callTimes = 0 == channelCallCfg.getSyncQueryRepeatNum() ? 1 : channelCallCfg.getSyncQueryRepeatNum();
            int gatTime = channelCallCfg.getSyncQueryRepeatTime();
            int gatType = StringUtil.isEmptyOrNull(channelCallCfg.getSyncQueryGapType()) ? 0 : Integer.parseInt(channelCallCfg.getSyncQueryGapType());
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.1：异步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.MOMP_PAYMENT_SERVICE_INNER_PATH);
                iReturnCode = dubboService.asynCallDubboInnerMethod(clasz, ShareServiceConstant.MOMP_COMBO_MCHNT_FEE_DISCOUNT_METHOD, comboMchntFeeDiscountRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.2：异步远程调用 */
                iReturnCode = dubboService.asynCallDubboService(ShareServiceConstant.MOMP_PAYMENT_SERVICE, ShareServiceConstant.MOMP_COMBO_MCHNT_FEE_DISCOUNT_METHOD, comboMchntFeeDiscountRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
            if (0 == iReturnCode) {
                return new BizResponse<>(OltpRpcdEnum.TRANS_SUCCESS.getRespCode(), OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            } else {
                return new BizResponse<>(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
            }
        } else {
            /* Step1.2：同步调用 */
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.1：同步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.MOMP_PAYMENT_SERVICE_INNER_PATH);
                callResult = (Result<ComboMchntFeeDiscountResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.MOMP_COMBO_MCHNT_FEE_DISCOUNT_METHOD, comboMchntFeeDiscountRequest);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.2：同步远程调用 */
                callResult = (Result<ComboMchntFeeDiscountResponse>) dubboService.callDubboService(ShareServiceConstant.MOMP_PAYMENT_SERVICE, ShareServiceConstant.MOMP_COMBO_MCHNT_FEE_DISCOUNT_METHOD, comboMchntFeeDiscountRequest);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
        }
        return callResult;
    }

    @Override
    public Object querySyncCallResult(PayOrderInfo payOrderInfo, Object request) {
        return null;
    }

    @Override
    public OrderInfo callResultOrderProc(OrderInfo orderInfo, String payOrderIndex, TransStatusEnum transStatusEnum, Object response) throws Exception {
        OrderInfo updateOrderInfo = new OrderInfo();
        Result<ComboMchntFeeDiscountResponse> callResult = (Result<ComboMchntFeeDiscountResponse>) response;
        Optional<PayOrderInfo> payOrderInfoOpt = orderInfo.getPayOrderInfoList().stream().filter(item -> item.getDstCallIndex().equals(payOrderIndex)).findFirst();
        if (payOrderInfoOpt.isPresent() && null != callResult && null != callResult.getResult()) {
            ComboMchntFeeDiscountResponse comboMchntFeeDiscountResponse = callResult.getResult();
            PayOrderInfo payOrderInfo = payOrderInfoOpt.get();
            payOrderInfo.setTransStatus(transStatusEnum.getStatus());
            payOrderInfo.setRespCode(comboMchntFeeDiscountResponse.getRespCode());
            payOrderInfo.setRespDesc(comboMchntFeeDiscountResponse.getRespDesc());
            payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            switch (transStatusEnum) {
                case TRANS_SUCC:
                    /* 支付订单信息处理 */
                    payOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                    payOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                    payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    payOrderInfo.setRespCode(comboMchntFeeDiscountResponse.getRespCode());
                    payOrderInfo.setRespDesc(comboMchntFeeDiscountResponse.getRespDesc());
                    /* 商户订单信息处理 */
                    MchntService mchntService = new MchntServiceImpl();
                    List<PaymentOrderMchntFeeDiscountInfoBean> orderDetailBeanList = comboMchntFeeDiscountResponse.getFeeOrderDetailList();
                    for (MchntOrderInfo mchntOrderInfo : orderInfo.getMchntOrderInfoList()) {
                        MchntInfo mchntInfo = mchntService.getMchntInfo(mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo());
                        String mchntNo = mchntInfo.getMchntNo();
                        if ("11".equals(mchntInfo.getMchntType()) && AppParamConstant.NO.equals(mchntInfo.getIndependentDataFlag())) {
                            mchntNo = mchntInfo.getChainMchntNo();
                        }
                        String finalMchntNo = mchntNo;
                        List<PaymentOrderMchntFeeDiscountInfoBean> paymentOrderDetailBeanList = orderDetailBeanList.stream().filter(item -> item.getMchntNo().equals(finalMchntNo)).collect(Collectors.toList());
                        /*商户手续费优惠金额*/
                        rglog.debug("商户:<{}>,营销手续费:<{}>,实收手续费<{}>", mchntOrderInfo.getMchntNo(), paymentOrderDetailBeanList.get(0).getMchntFeeDiscount(), paymentOrderDetailBeanList.get(0).getMchntFeeActual());
                        /*商户优惠手续费*/
                        mchntOrderInfo.setMchntDiscountFee(paymentOrderDetailBeanList.get(0).getMchntFeeDiscount());
                        /*商户手续处理商户实收手续费*/
                        mchntOrderInfo.setRealMchntFee(paymentOrderDetailBeanList.get(0).getMchntFeeActual());
                        /*商户实际清算金额=商户实际清算金额-商户实收手续费*/
                        mchntOrderInfo.setMchntSettleAmt(AmountUtil.subtraction(mchntOrderInfo.getRealSettleAmt(), mchntOrderInfo.getRealMchntFee()));
                        mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    }
                    break;
                case TRANS_TIMEOUT:
                    payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                    break;
                case SYSTEM_REJECT:
                    rglog.error("手续费营销返回异常，商户不享受手续营销");
                    payOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    payOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                    payOrderInfo.setRespCode(callResult.getResult().getRespCode());
                    payOrderInfo.setRespDesc(callResult.getResult().getRespDesc());
                    payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    break;
                default:
                    break;
            }
            updateOrderInfo.setPayOrderInfoList(Collections.singletonList(payOrderInfo));
        }
        updateOrderInfo.setMchntOrderInfoList(orderInfo.getMchntOrderInfoList());
        return updateOrderInfo;
    }

    /**
     * 根据支付账户类型转换费率类型
     *
     * @param payerAcctType 支付账户类型
     * @return 费率类型
     */
    private String convFeeType(String payerAcctType) {
        String feeType;
        if (AcctTypeEnum.BANK_CREDIT.getAcctType().equals(payerAcctType)) {
            feeType = FeeTypeEnum.BANK_CR_CARD.getFeeType();
        } else if (AcctTypeEnum.BANK_DEBIT.getAcctType().equals(payerAcctType)) {
            feeType = FeeTypeEnum.BANK_DR_CARD.getFeeType();
        } else if (AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(payerAcctType)) {
            feeType = FeeTypeEnum.OTHER_BANK_DR_CARD.getFeeType();
        } else {
            feeType = FeeTypeEnum.OTHER_BANK_CR_CARD.getFeeType();
        }
        return feeType;
    }
}
